/**
 *	printError, shaderfilelength, readShaderFile, createShader is
 *	written by Stefan Gustavsson
 */



/*
 * printError - Signal an error.
 */
void printError(const char *errtype, const char *errmsg) {
	fprintf(stderr, "%s: %s\n", errtype, errmsg);
}


/*
 * filelength - Determine the number of bytes in a file.
 * This is a lazy hack to avoid calling stat(), but it works.
 */
int shaderfilelength(const char *filename) {
	FILE *ifp;
	int length = 0;
	
	ifp = fopen(filename, "r");
	fseek(ifp, 0, SEEK_END);
	length = (int)ftell(ifp);
	fclose(ifp);
	return length;
}
unsigned char* readShaderFile(const char *filename) {
	FILE *file = fopen(filename, "r");
	if(file == NULL)
    {
		printError("I/O error", "Cannot open shader file!");
		return 0;
    }
	int bytesinfile = shaderfilelength(filename);
	unsigned char *buffer = (unsigned char*)malloc(bytesinfile+1);
	int bytesread = fread( buffer, 1, bytesinfile, file);
	buffer[bytesread] = 0; // Terminate the string with 0
	fclose(file);
	
	return buffer;
}

GLhandleARB createShader(const char *vertfilename, const char *fragfilename) {
	
	GLhandleARB programObj;
	GLhandleARB fragmentShader;
	GLhandleARB vertexShader;
	const char *vertexShaderStrings[1];
	GLint vertexCompiled;
	const char *fragmentShaderStrings[1];
	GLint fragmentCompiled;
	GLint shadersLinked;
	char str[4096]; // For error messages from the GLSL compiler and linker
	
	// Create the vertex and fragment shaders
	vertexShader = glCreateShaderObjectARB( GL_VERTEX_SHADER_ARB );
	
	char *vertexShaderAssembly = readShaderFile( vertfilename );
	vertexShaderStrings[0] = vertexShaderAssembly;
	glShaderSourceARB( vertexShader, 1, vertexShaderStrings, NULL );
	glCompileShaderARB( vertexShader );
	free((void *)vertexShaderAssembly);
	
	glGetObjectParameterivARB( vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, 
							  &vertexCompiled );
	if(vertexCompiled == GL_FALSE)
    {
		glGetInfoLogARB( vertexShader, sizeof(str), NULL, str );
		printError("Vertex shader compile error", str);
    }
	
	fragmentShader = glCreateShaderObjectARB( GL_FRAGMENT_SHADER_ARB );
	
	char *fragmentShaderAssembly = readShaderFile( fragfilename );
	fragmentShaderStrings[0] = fragmentShaderAssembly;
	glShaderSourceARB( fragmentShader, 1, fragmentShaderStrings, NULL );
	glCompileShaderARB( fragmentShader );
	free((void *)fragmentShaderAssembly);
	
	glGetObjectParameterivARB( fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, 
							  &fragmentCompiled );
	if(fragmentCompiled == GL_FALSE)
    {
		glGetInfoLogARB( fragmentShader, sizeof(str), NULL, str );
		printError("Fragment shader compile error", str);
    }
	
	// Create a program object and attach the compiled shaders
	programObj = glCreateProgramObjectARB();
	glAttachObjectARB( programObj, vertexShader );
	glAttachObjectARB( programObj, fragmentShader );
	
	// Link the program object and print out the info log
	glLinkProgramARB( programObj );
	glGetObjectParameterivARB( programObj, GL_OBJECT_LINK_STATUS_ARB, &shadersLinked );
	
	if( shadersLinked == GL_FALSE )
    {
		glGetInfoLogARB( programObj, sizeof(str), NULL, str );
		printError("Program object linking error", str);
    }
	
	return programObj;
}

void ExitFunction(void)
{
	
	glUseProgramObjectARB(0);
	
	//glDeleteProgram(waterShader);
}
